package com.code.zg.rxapplication.ui;

import android.content.Context;
import android.content.Intent;
import android.content.pm.ResolveInfo;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.os.StrictMode;
import android.support.annotation.NonNull;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.util.TypedValue;
import android.view.View;
import android.widget.Toast;

import com.code.zg.rxapplication.R;
import com.code.zg.rxapplication.adapter.ApplicationAdapter;
import com.code.zg.rxapplication.bean.AppInfo;
import com.code.zg.rxapplication.bean.AppInfoRich;
import com.code.zg.rxapplication.utils.Utils;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;

import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.Unbinder;
import rx.Observable;
import rx.Subscriber;
import rx.android.schedulers.AndroidSchedulers;
import rx.functions.Func1;
import rx.functions.Func2;
import rx.joins.Plan0;
import rx.observables.GroupedObservable;
import rx.observables.JoinObservable;

/**
 * eg 01
 */
public class APPActivity extends AppCompatActivity {
    private static final String TAG = "tag";
    private Context mContext=APPActivity.this;
    @BindView(R.id.swipe)
    SwipeRefreshLayout swipe;
    @BindView(R.id.recycler)
    RecyclerView recycler;
    private ApplicationAdapter adapter;
    private Unbinder bind;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_app);
        bind = ButterKnife.bind(this);
        StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().detectAll().penaltyLog().build());
        StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectAll().penaltyLog().build());
        initView();
//        loadData();
//            loadData2();
//        loadData3();
//        loadData4();
//        loadData5();
//        loadData6();
//        loadData7();
//        loadData8();
        loadData9();
    }
    private void loadData9(){
        Observable<AppInfo> from = Observable.from(getAllApps2());
        Observable<Long> interval = Observable.interval(1, TimeUnit.SECONDS);
        Plan0<AppInfo> plan0 = JoinObservable.from(from).and(interval).then(new Func2<AppInfo, Long, AppInfo>() {
            @Override
            public AppInfo call(AppInfo appInfo, Long aLong) {
                appInfo.setmName(aLong+" "+appInfo.getmName());
                return appInfo;
            }
        });
        JoinObservable.when(plan0).toObservable().observeOn(AndroidSchedulers.mainThread()).subscribe(new Subscriber<AppInfo>() {
            @Override
            public void onCompleted() {
                Log.i(TAG, "onCompleted: ");
                Toast.makeText(mContext, "completed", Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onError(Throwable e) {
                Log.i(TAG, "onError: "+e.getMessage());
                swipe.setRefreshing(false);
            }

            @Override
            public void onNext(AppInfo info) {
                recycler.setVisibility(View.VISIBLE);
                adapter.addApplication(info,adapter.getItemCount());
                swipe.setRefreshing(false);
                Log.i(TAG, "onNext: "+info.getmName());
            }
        });

    }
    private void loadData8(){
//        join  失败
//        Observable<AppInfo> appsequence = Observable.interval(1, TimeUnit.SECONDS).map(new Func1<Long, AppInfo>() {
//            @Override
//            public AppInfo call(Long aLong) {
//                return getAllApps2().get(aLong.intValue());
//            }
//        });
//        Observable<Long> interval = Observable.interval(1, TimeUnit.SECONDS);
//        appsequence.join(interval, new Func1<AppInfo, Observable<Long>>() {
//            @Override
//            public Observable<Long> call(AppInfo info) {
//                return Observable.timer(2, TimeUnit.SECONDS);
//            }
//        }, new Func1<Long, Observable<Long>>() {
//            @Override
//            public Observable<Long> call(Long aLong) {
//                return Observable.timer(0,TimeUnit.SECONDS);
//            }
//        }, updateTitle(null,));

    }
    private AppInfo updateTitle(AppInfo appInfo,long time){
        appInfo.setmName(time+" "+appInfo.getmName());
        return appInfo;

    }
    private void loadData7(){
        Observable<AppInfo> app1 = Observable.from(getAllApps2()).take(5);
        Observable<Long> interval = Observable.interval(1, TimeUnit.SECONDS);
        Observable.zip(app1, interval, new Func2<AppInfo, Long, AppInfo>() {
            @Override
            public AppInfo call(AppInfo info, Long aLong) {
                info.setmName(info.getmName()+aLong);
                return info;
            }
        }).observeOn(AndroidSchedulers.mainThread()).subscribe(new Subscriber<AppInfo>() {
            @Override
            public void onCompleted() {
                Log.i(TAG, "onCompleted: ");
                Toast.makeText(mContext, "completed", Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onError(Throwable e) {
                Log.i(TAG, "onError: "+e.getMessage());
                swipe.setRefreshing(false);
            }

            @Override
            public void onNext(AppInfo info) {
                recycler.setVisibility(View.VISIBLE);
                adapter.addApplication(info,adapter.getItemCount());
                swipe.setRefreshing(false);
                Log.i(TAG, "onNext: "+info.getmName());
            }
        });

    }
    private void loadData6(){
        Observable<AppInfo> app1 = Observable.from(getAllApps2()).take(3);
        Observable<AppInfo> app2 = Observable.from(getAllAppsReverse()).take(3);
        Observable.merge(app1,app2).subscribe(new Subscriber<AppInfo>() {
            @Override
            public void onCompleted() {
                Log.i(TAG, "onCompleted: ");
                Toast.makeText(mContext, "completed", Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onError(Throwable e) {
                Log.i(TAG, "onError: "+e.getMessage());
                swipe.setRefreshing(false);
            }

            @Override
            public void onNext(AppInfo info) {
                recycler.setVisibility(View.VISIBLE);
                adapter.addApplication(info,adapter.getItemCount());
                swipe.setRefreshing(false);
                Log.i(TAG, "onNext: "+info.getmName());
            }
        });

    }
    private void loadData5(){
        Observable<GroupedObservable<String, AppInfo>> groupedObservableObservable = Observable.from(getAllApps2()).
                map(new Func1<AppInfo, AppInfo>() {
                    @Override
                    public AppInfo call(AppInfo info) {
                        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("dd/MM/yyyy");
                        String format = simpleDateFormat.format(info.getmLastUpdateTime());
                        info.setmName(format);
                        return info;
                    }
                }).groupBy(new Func1<AppInfo, String>() {
            @Override
            public String call(AppInfo appInfoRich) {
                SimpleDateFormat simpleDateFormat = new SimpleDateFormat("MM/yyyy");
                return simpleDateFormat.format(appInfoRich.getmLastUpdateTime());
            }
        });
        Observable.concat(groupedObservableObservable).subscribe(new Subscriber<AppInfo>() {
            @Override
            public void onCompleted() {
                Log.i(TAG, "onCompleted: ");
                Toast.makeText(mContext, "completed", Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onError(Throwable e) {
                Log.i(TAG, "onError: "+e.getMessage());
                swipe.setRefreshing(false);
            }

            @Override
            public void onNext(AppInfo info) {
                recycler.setVisibility(View.VISIBLE);
                adapter.addApplication(info,adapter.getItemCount());
                swipe.setRefreshing(false);
                Log.i(TAG, "onNext: "+info.getmName());
            }
        });
    }
    private void loadData4(){
        Observable.from(getAllApps2()).scan(new Func2<AppInfo, AppInfo, AppInfo>() {
            @Override
            public AppInfo call(AppInfo info, AppInfo info2) {
                if(info.getmName().length()>info2.getmName().length()){
                    return info;
                }else{
                    return info2;
                }
            }
        }).subscribe(new Subscriber<AppInfo>() {
            @Override
            public void onCompleted() {
                Log.i(TAG, "onCompleted: ");
                Toast.makeText(mContext, "completed", Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onError(Throwable e) {
                Log.i(TAG, "onError: "+e.getMessage());
                swipe.setRefreshing(false);
            }

            @Override
            public void onNext(AppInfo info) {
                recycler.setVisibility(View.VISIBLE);
                adapter.addApplication(info,adapter.getItemCount()-1);
                swipe.setRefreshing(false);
                Log.i(TAG, "onNext: "+info.getmName());
            }
        });
    }
    private void loadData3(){
//        Observable.from(getAllApps2()).map(new Func1<AppInfo, AppInfo>() {
//            @Override
//            public AppInfo call(AppInfo info) {
//                return null;
//            }
//        }).flatMap(new Func1<AppInfo, Observable<AppInfo>>() {
//            @Override
//            public Observable<AppInfo> call(final AppInfo info) {
//
//                return Observable.create(new Observable.OnSubscribe<AppInfo>() {
//                    @Override
//                    public void call(Subscriber<? super AppInfo> subscriber) {
//                        subscriber.onNext(info);
//                    }
//                });
//            }
//        }).subscribe();
        Observable.from(getAllApps2()).map(new Func1<AppInfo, AppInfo>() {
            @Override
            public AppInfo call(AppInfo info) {
                String s = info.getmName();
                String s1 = s.toLowerCase();
                info.setmName(s1);

                return info;
            }
        }).subscribe(new Subscriber<AppInfo>() {
            @Override
            public void onCompleted() {
                Log.i(TAG, "onCompleted: ");
                Toast.makeText(mContext, "completed", Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onError(Throwable e) {
                Log.i(TAG, "onError: "+e.getMessage());
                swipe.setRefreshing(false);
            }

            @Override
            public void onNext(AppInfo info) {
                recycler.setVisibility(View.VISIBLE);
                adapter.addApplication(info,adapter.getItemCount()-1);
                swipe.setRefreshing(false);
                Log.i(TAG, "onNext: "+info.getmName());
            }
        });
    }
    private void loadData2() {
        Observable.from(getAllApps2()).subscribe(new Subscriber<AppInfo>() {
            @Override
            public void onCompleted() {
                Log.i(TAG, "onCompleted: ");
                Toast.makeText(mContext, "completed", Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onError(Throwable e) {
                Log.i(TAG, "onError: "+e.getMessage());
                swipe.setRefreshing(false);
            }

            @Override
            public void onNext(AppInfo info) {
                recycler.setVisibility(View.VISIBLE);
                adapter.addApplication(info,adapter.getItemCount()-1);
                swipe.setRefreshing(false);
                Log.i(TAG, "onNext: "+info.getmName());
            }
        });
    }

    private void loadData() {
        getApps().toSortedList().subscribe(new Subscriber<List<AppInfo>>() {
            @Override
            public void onCompleted() {
                Log.i(TAG, "onCompleted: ");
                swipe.setRefreshing(false);
                Toast.makeText(mContext, "completed", Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onError(Throwable e) {
                Log.i(TAG, "onError: "+e.getMessage());
                swipe.setRefreshing(false);
            }

            @Override
            public void onNext(List<AppInfo> appInfos) {
                recycler.setVisibility(View.VISIBLE);
                adapter.addApplication(appInfos);
                Log.i(TAG, "onNext: "+appInfos.toString());
                for (AppInfo appInfo : appInfos) {
                    Log.i(TAG,appInfo.getmName());
                }
            }
        });
    }

    private void initView() {
        recycler.setLayoutManager(new LinearLayoutManager(mContext));
        adapter=new ApplicationAdapter();
        recycler.setAdapter(adapter);
        swipe.setColorSchemeColors(getResources().getColor(R.color.myPrimaryColor));
        swipe.setProgressViewOffset(false,0,(int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,24,getResources().getDisplayMetrics()));
        swipe.setEnabled(false);
        swipe.setRefreshing(true);
        recycler.setVisibility(View.GONE);
    }
    //1方式一
    private Observable<AppInfo>getApps(){
        return Observable.unsafeCreate(new Observable.OnSubscribe<AppInfo>() {
            @Override
            public void call(Subscriber<? super AppInfo> subscriber) {
                List<AppInfoRich> appInfoRiches = getAllApps();
                for(AppInfoRich appInfoRich:appInfoRiches){
                    Bitmap icon= Utils.drawableToBitmap(appInfoRich.getIcon());
                    String name=appInfoRich.getmName();
                    String filePath=getFilesDir()+ File.separator+name;
//                    Utils.blockStoreBitmap(mContext,icon,name);
                    Utils.storeBitmap(mContext,icon,name);
                    if(subscriber.isUnsubscribed()){
                        return;
                    }

                    subscriber.onNext(new AppInfo(name,appInfoRich.getLastUpdateTime(),filePath));
                }
                subscriber.onCompleted();
            }
        });

    }

    @NonNull
    private List<AppInfoRich> getAllApps() {
        List<AppInfoRich>appInfoRiches=new ArrayList<AppInfoRich>();
        Intent intent = new Intent(Intent.ACTION_MAIN, null);
        intent.addCategory(Intent.CATEGORY_LAUNCHER);
        List<ResolveInfo> resolveInfos = getPackageManager().queryIntentActivities(intent, 0);
        for(ResolveInfo resolveInfo:resolveInfos){
            appInfoRiches.add(new AppInfoRich(mContext,resolveInfo));
        }
        return appInfoRiches;
    }
    private List<AppInfo>getAllAppsReverse(){
        List<AppInfo> allApps2 = getAllApps2();
        Collections.reverse(allApps2);
        return allApps2;
    }
    //方式2
    @NonNull
    private List<AppInfo> getAllApps2() {
        List<AppInfoRich>appInfoRiches=new ArrayList<AppInfoRich>();
        Intent intent = new Intent(Intent.ACTION_MAIN, null);
        intent.addCategory(Intent.CATEGORY_LAUNCHER);
        List<ResolveInfo> resolveInfos = getPackageManager().queryIntentActivities(intent, 0);
        for(ResolveInfo resolveInfo:resolveInfos){
            appInfoRiches.add(new AppInfoRich(mContext,resolveInfo));
        }
        List<AppInfo>appInfo=new ArrayList<AppInfo>();

        for(AppInfoRich appInfoRich:appInfoRiches){
            Bitmap icon= Utils.drawableToBitmap(appInfoRich.getIcon());
            String name=appInfoRich.getmName();
            String filePath=getFilesDir()+ File.separator+name;
//                    Utils.blockStoreBitmap(mContext,icon,name);
            Utils.storeBitmap(mContext,icon,name);
            appInfo.add(new AppInfo(name,appInfoRich.getLastUpdateTime(),filePath));
        }

        return appInfo;
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        bind.unbind();
    }
}
